// Copyright 2009 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#ifndef POPDIAG_CONFIG_CONFIGVERIFIER_H__
#define POPDIAG_CONFIG_CONFIGVERIFIER_H__

#include <QtCore/QString>
#include <QtCore/QList>
#include <QtCore/QObject>
#include <QtCore/QPair>

#include "util/common.h"
#include "util/protocol.h"


namespace popdiag {

typedef enum {
    UNKNOWN,

    PROFILE_NOT_UNDERSTOOD ,
    POP3_SERVER,
    POP3_PORT,
    POP3_USE_SSL,
    POP3_LEAVE_ON_SERVER,
    POP3_USE_SPA,
    POP3_USERNAME,
    POP3_TIMEOUT,
    POP3_ACCOUNT_SKIPPED,

    SMTP_SERVER,
    SMTP_PORT_465,  // port should be 465, isn't
    SMTP_PORT_587,  // should be 587, isn't
    SMTP_USE_AUTH,
    SMTP_USE_SSL,
    SMTP_USERNAME,
    SMTP_USE_SPA,
    SMTP_SPLIT_MESSAGES,
    SMTP_TIMEOUT,
    SMTP_EMAIL_ADDRESS,
    SMTP_AUTH_POP_BEFORE_SMTP,

    IMAP_SERVER,
    IMAP_PORT,
    IMAP_USE_SSL,
    IMAP_USE_SPA,
    IMAP_USERNAME,
    IMAP_FOLDER_PATH,
} FaultId;

// a fault consists of a fault ID and an optional QString.
typedef QPair<FaultId, QString> Fault;

// Given a fault, render a description in the local
// language:
QString FaultDescription(const Fault &f);

typedef QList<Fault> FaultSet;

// A verification result represents a configuration
// inspection of a single profile in a single
// program.  Via the Recalculate() method they can
// be re-invoked to check for corrections or new
// faults.
class VerificationResult : public QObject {
  Q_OBJECT;
 public:
  enum ServerType {
    SERVERTYPE_POP,
    SERVERTYPE_IMAP
  };

  VerificationResult();
  virtual ~VerificationResult();

  // The name of the mail reader, to be displayed to the user.
  const QString &program_name() const;

  // If true, this is the system default mail reader.
  bool is_default_program() const;

  // A short code for the mail reader.
  const QString &program_code() const;

  // A description of this profile.  A profile is a collection
  // of account settings. An "Account" in Outlook, for example.
  const QString &profile_name() const;

  // If true, this is the profile this mail reader uses by default.
  bool is_default_profile() const;

  // The protocol (POP or IMAP) to be displayed.
  const QString &display_protocol() const;

  // The email address to diplay for this profile.  Should be derived from
  // the address used to authenticate to POP.
  const QString &display_email() const;

  // The user's name, as rendered on sent email.
  const QString &display_name() const;

  // The faults we found with this configuration.
  const FaultSet &faults() const;

  // Servers and ports we found.
  const QString& imap_server() const {
    return imap_server_;
  }
  const QString& pop_server() const {
    return pop_server_;
  }
  const QString& smtp_server() const {
    return smtp_server_;
  }
  int smtp_port() const {
    return smtp_port_;
  }

  // Request that this profile be re-examined.
  virtual void Recalculate(const QString &email_address) = 0;

  // May contain a dump of configuration, notes from scrubber, etc.
  // Not intended for display to end users.
  const QString &debug_text() const;

  void set_program_name(const QString &n);
  void set_program_code(const QString &n);
  void set_profile_name(const QString &n);
  void set_display_protocol(const QString &n);
  void set_display_email(const QString &n);
  void set_display_name(const QString &n);
  void set_faults(const FaultSet &s);
  void set_debug_text(const QString &n);
  void set_is_default_program(bool n);
  void set_is_default_profile(bool n);
 protected:
  void ClearLog();
  void StartLogDetails();
  void LogDetails(const QString &step, bool good,
                  const QString &details);
  void EndLogDetails();

  QString program_name_;
  QString program_code_;
  QString profile_name_;
  QString display_protocol_;
  QString display_email_;
  QString display_name_;
  bool is_default_program_;
  bool is_default_profile_;
  FaultSet faults_;
  QString imap_server_;
  QString pop_server_;
  QString smtp_server_;
  int smtp_port_;

  void InitProtocolDependentValues();

  // these are initialized by InitProtocolDependentValues()
  enum ServerType server_type_;
  QString protocol_name_;
  FaultId username_fault_;
  const Protocol *protocol_;
  FaultId server_fault_;
  FaultId use_ssl_fault_;
  FaultId port_fault_;
  int ssl_port_;
  int plaintext_port_;
  QString *incoming_server_;

  // for verification and logging of incoming server settings
  void CheckIncomingSettings();

  // note that these match integer values in the Thunderbird configuration
  typedef enum {
    PLAINTEXT = 0,
    TLS_IF_AVAILABLE = 1,
    TLS = 2,
    SSL = 3
  } SocketType;
  QString incoming_server_name_;
  QString incoming_user_name_;
  SocketType incoming_socket_type_;
  int incoming_port_;
  bool leave_on_server_;

  // for verification and logging of outgoing server settings
  void CheckOutgoingSettings();

  QString smtp_username_;
  QString email_;
  QString smtp_email_;
  bool smtp_use_auth_;
  SocketType smtp_socket_type_;

 private:
  QString debug_text_;

  DISALLOW_EVIL_CONSTRUCTORS(VerificationResult);
};

typedef QList<VerificationResult*> VerificationSet;

// A ConfigVerifier looks at a program and finds
// interesting profiles to inspect.  It constructs
// a VerificationSet containing one entry for
// each interesting profile.
class ConfigVerifier : public QObject {
  Q_OBJECT;
 public:
  ConfigVerifier();
  virtual ~ConfigVerifier();

  virtual QString program_name() const = 0;

  // returns true if this client seems to be installed and has one
  // or more relevant profiles.  out will be filled in with the
  // configuration check results for this client.
  // Caller must delete the contents of *out.
  virtual bool CheckConfiguration(VerificationSet *out) const = 0;
 private:
  DISALLOW_EVIL_CONSTRUCTORS(ConfigVerifier);
};

// A ConfigChecker holds a registry of known
// ConfigVerifier classes and runs each of them against
// the given username.
class ConfigChecker : public QObject {
  Q_OBJECT;
 public:
  explicit ConfigChecker(QObject *parent);
  ~ConfigChecker();

 public slots:
  void GatherConfigDetails(VerificationSet *results);

 signals:
  void OnConfigsChecked(const VerificationSet &results);
};

class ConfigVerifierRegistry {
 public:
  static void GetVerifiers(QList<ConfigVerifier *> *verifiers);

  // fetch the "basename" of the executable that is the default mail
  // application.  Note that this might be a windows "short name".
  static QString GetDefaultMailProgramBaseName();
};

}  // namespace popdiag

#endif  // POPDIAG_CONFIG_CONFIGVERIFIER_H__
